#include "iot_errno.h"
#include "iot_uart.h"
#include "iot_gpio.h"
#include "stm32f4xx_ll_usart.h"
#include "stm32f4xx_ll_bus.h"
#include "ll_gpio.h"
#include "ll_uart.h"
#include "queue.h"
#include "stdio.h"

// 串口配置信息
extern UART_Config g_uartConfig[UART_MAX];

unsigned int IoTUartInit(unsigned int id, const IotUartAttribute *param)
{
    // 串口id，stm32f407只有6个uart，分别是USART1, USART2, USART3, UART4, UART5, USART6
    if (id > UART_MAX || id < 1){
        printf("%s line %d error : bad uart id, for stm32f407 uart id is 1~6...\r\n", __func__, __LINE__);
        return IOT_FAILURE;
    }
    // 非法参数
    if (NULL == param){
        printf("%s line %d error : uart param is null...\r\n", __func__, __LINE__);
        return IOT_FAILURE;
    }
    // 初始化引脚
    if (LL_UART_CONFIG_Init(id) == ERROR){
        printf("%s line %d error : config uart gpio pin failed...\r\n", __func__, __LINE__);
        return IOT_FAILURE;
    }
    
    switch (id)
    {
    case 1:
        // 打开时钟
        LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_USART1);
        break;
    case 2:
        LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_USART2);
        break;
    case 3:
        LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_USART3);
        break;
    case 4:
        LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_UART4);
        break;
    case 5:
        LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_UART5);
        break;
    case 6:
        LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_USART6);
        break;
    }
    // 串口配置
    g_uartConfig[id-1].luart.BaudRate = param->baudRate;
    g_uartConfig[id-1].luart.DataWidth = param->dataBits;
    g_uartConfig[id-1].luart.StopBits = param->stopBits;
    g_uartConfig[id-1].luart.Parity = param->parity;
    g_uartConfig[id-1].luart.TransferDirection = LL_USART_DIRECTION_TX_RX;
    g_uartConfig[id-1].luart.HardwareFlowControl = LL_USART_HWCONTROL_NONE;
    g_uartConfig[id-1].luart.OverSampling = LL_USART_OVERSAMPLING_16;
    // 初始化串口
    if (LL_USART_Init(g_uartConfig[id-1].UARTx, &g_uartConfig[id-1].luart) != SUCCESS)
    {
        printf("%s line %d error : LL_USART_Init failed...\r\n", __func__, __LINE__);
        return IOT_FAILURE;
    }
    // 使用异步通信模式
    LL_USART_ConfigAsyncMode(g_uartConfig[id-1].UARTx);
    // dma
	LL_UART_DMA_Init(id);
    // 创建中断
    IoTUartRegisterIsrFunc(id, g_uartConfig[id-1].recvHandler);
	// 创建队列
    if(QueueCreate(&g_uartConfig[id-1].recvID, 1, g_uartConfig[id-1].recvLen)!=SUCCESS){
        printf("%s line %d error : queue_create create uart recMsg queue failed...\r\n", __func__, __LINE__);
        return IOT_FAILURE;
    }
    #if 0
    printf("**************************************************************************\r\n");
    printf("* UART init success! Please pay attention to the following information   *\r\n");
    printf("**************************************************************************\r\n");
    printf("* Use default config for UART, see Tabel UART-Pin.                       *\r\n");
    printf("* For stm32f407 uart port is 1~6                                         *\r\n");
    printf("* If you want change uart pin, please modify macro :                     *\r\n");
    printf("*    UARTx_RX, UART Rx pin id. eg: UART1_RX/UART2_RX..                   *\r\n");
    printf("*    UARTx_TX, UART Tx pin id. eg: UART1_TX/UART2_TX..                   *\r\n");
    printf("* About pin id, see iot_gpio driver                                      *\r\n");
    printf("**************************************************************************\r\n");
    #endif
    return IOT_SUCCESS;
}

void IoTUartRegisterIsrFunc(unsigned int id, UartIsrCallbackFunc func)
{
    // 关闭中断
    LL_USART_Disable(g_uartConfig[id-1].UARTx);
    LL_DMA_DisableStream(g_uartConfig[id-1].dma, g_uartConfig[id-1].rxStream);
    LL_USART_DisableDMAReq_RX(g_uartConfig[id-1].UARTx);
    LL_USART_DisableIT_IDLE(g_uartConfig[id-1].UARTx);
    // 配置中断参数
    NVIC_DisableIRQ(g_uartConfig[id-1].UART_IRQn);
    NVIC_SetVector(g_uartConfig[id-1].UART_IRQn, (uint32_t)func);
    NVIC_SetPriority(g_uartConfig[id-1].UART_IRQn, 0);
    NVIC_EnableIRQ(g_uartConfig[id-1].UART_IRQn);
    // 使能串口
    LL_USART_Enable(g_uartConfig[id-1].UARTx);
    LL_USART_EnableDMAReq_RX(g_uartConfig[id-1].UARTx);
    // 清空空闲中断
    LL_USART_ClearFlag_IDLE(g_uartConfig[id-1].UARTx);
    // 打开空闲中断
    LL_USART_EnableIT_IDLE(g_uartConfig[id-1].UARTx);
    // 启用DMA中断
    LL_DMA_EnableIT_TC(g_uartConfig[id - 1].dma, g_uartConfig[id - 1].rxStream);
    LL_DMA_EnableIT_TE(g_uartConfig[id - 1].dma, g_uartConfig[id - 1].rxStream);
    // 开启dma
    LL_DMA_EnableStream(g_uartConfig[id-1].dma, g_uartConfig[id-1].rxStream);
}

int IoTUartReadTimeout(unsigned int id, unsigned char *data, unsigned int dataLen, unsigned int tick)
{
    // 检测参数
    if (id > UART_MAX || id < 1)
    {
        printf("%s line %d error : bad uart id, for stm32f407 uart id is 1~6...\r\n", __func__, __LINE__);
        return IOT_FAILURE;
    }
    if(data == NULL)
    {
        printf("%s line %d error : bad recv buf pointer...\r\n", __func__, __LINE__);
        return IOT_FAILURE;
    }

    uint8_t tmp_len = 1;
    uint32_t i=0;
    uint64_t start_tick, end_tick;
    start_tick = LL_GetTick();
    // 循环读取，直到超时
    while(i<dataLen)
    {
        char u_data;
        if (QueueOut(g_uartConfig[id-1].recvID, &u_data) == SUCCESS){
            data[i] = u_data;
            i++;
        }
        end_tick = LL_GetTick();
        if (end_tick - start_tick > tick){
            break;
        }
    }
    return i;
}

int IoTUartRead(unsigned int id, unsigned char *data, unsigned int dataLen)
{
    if(g_uartConfig[id-1].rxBlock){
        printf("read timeout\r\n");
        return IoTUartReadTimeout(id, data, dataLen, UART_RX_TIMEOUT);
    }
    else{
        printf("read noe \r\n");
        return IoTUartReadTimeout(id, data, dataLen, 0);
    }
}

int IoTUartWrite(unsigned int id, const unsigned char *data, unsigned int dataLen)
{
    if (id > UART_MAX || id < 1){
        //printf("%s line %d error : bad uart id, for stm32f407 uart id is 1~6...\r\n", __func__, __LINE__);
        return IOT_FAILURE;
    }

    uint64_t start_tick, end_tick;
    for (uint32_t i = 0; i < dataLen; i++){
        start_tick = LL_GetTick();
        // 等待发送寄存器为空
        while (!LL_USART_IsActiveFlag_TXE(g_uartConfig[id-1].UARTx)){
            end_tick = LL_GetTick();
            if (end_tick - start_tick > 1000 * 10)
                return i;
        }
        // 发送数据
        LL_USART_TransmitData8(g_uartConfig[id-1].UARTx, data[i]);
    }
    start_tick = LL_GetTick();
    // 等待发送完成
    while (!LL_USART_IsActiveFlag_TC(g_uartConfig[id-1].UARTx)){
        end_tick = LL_GetTick();
        if (end_tick - start_tick > 1000 * 10)
            return dataLen - 1;
    }
    return dataLen;
}

unsigned int IoTUartDeinit(unsigned int id)
{
    if (id > UART_MAX || id < 1){
        printf("%s line %d error : bad uart id, for stm32f407 uart id is 1~6...\r\n", __func__, __LINE__);
        return IOT_FAILURE;
    }

    // 复位GPIO
    GPIO_TypeDef* GPIOx = LL_GET_GPIOX((g_uartConfig[id-1].rxPin)/16);
    if(LL_GPIO_DeInit(GPIOx) != SUCCESS){
        printf("%s error : LL_GPIO_DeInit UART Rx Pin failed\r\n", __func__);
        return IOT_FAILURE;
    }
    GPIOx = LL_GET_GPIOX((g_uartConfig[id-1].txPin)/16);
    if(LL_GPIO_DeInit(GPIOx) != SUCCESS){
        printf("%s error : LL_GPIO_DeInit UART Tx Pin failed\r\n", __func__);
        return IOT_FAILURE;
    }
    // 复位串口
    if (LL_USART_DeInit(g_uartConfig[id-1].UARTx) != SUCCESS){
        printf("%s line %d error : LL_USART_DeInit failed...\r\n", __func__, __LINE__);
        return IOT_FAILURE;
    }
    QueueDestroy(g_uartConfig[id-1].recvID);
    NVIC_DisableIRQ(g_uartConfig[id-1].UART_IRQn);
    LL_UART_DMA_DeInit(id);
    return IOT_SUCCESS;
}

unsigned int IoTUartSetFlowCtrl(unsigned int id, IotFlowCtrl flowCtrl)
{
    if (id > UART_MAX || id < 1){
        printf("%s line %d error : bad uart id, for stm32f407 uart id is 1~6...\r\n", __func__, __LINE__);
        return IOT_FAILURE;
    }
    // 修改流控参数
    if (flowCtrl == IOT_FLOW_CTRL_NONE){
        g_uartConfig[id-1].luart.HardwareFlowControl = LL_USART_HWCONTROL_NONE;
    }
    else if (flowCtrl == IOT_FLOW_CTRL_RTS_CTS){
        g_uartConfig[id-1].luart.HardwareFlowControl = LL_USART_HWCONTROL_RTS_CTS;
    }
    else if (flowCtrl == IOT_FLOW_CTRL_RTS_ONLY){
        g_uartConfig[id-1].luart.HardwareFlowControl = LL_USART_HWCONTROL_RTS;
    }
    else if (flowCtrl == IOT_FLOW_CTRL_CTS_ONLY){
        g_uartConfig[id-1].luart.HardwareFlowControl = LL_USART_HWCONTROL_CTS;
    }
    // 重新初始化串口
    if (LL_USART_Init(g_uartConfig[id-1].UARTx, &g_uartConfig[id-1].luart) != SUCCESS){
        printf("%s line %d error : LL_USART_Init failed...\r\n", __func__, __LINE__);
        return IOT_FAILURE;
    }
    return IOT_SUCCESS;
}